home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 12 / BBS in a box XII-1.iso / Files / System7 tools / Frontier / Frontier SDK 2.1.sit / Frontier SDK 2.1 / Extras / Droplet Developer / THINK C Source / droplet.c / droplet.c
Encoding:
C/C++ Source or Header  |  1993-06-09  |  25.4 KB  |  1,452 lines  |  [TEXT/KAHL]

  1.  
  2. /*© Copyright 1992 UserLand Software, Inc.  All Rights Reserved.*/
  3.  
  4.  
  5. #include <AppleEvents.h>
  6. #include <Aliases.h>
  7. #include <GestaltEqu.h>
  8. #include <Folders.h>
  9. #include <iac.h>
  10. #include <menusharing.h>
  11.  
  12.  
  13.  
  14. #define modelessid 130
  15. #define runitem 1
  16. #define cancelitem 2
  17. #define msgitem 3
  18. #define edititem 4
  19. #define iconitem 5
  20. #define titleitem 6
  21.     
  22. DialogPtr w;
  23.  
  24. #define applemenu 128
  25. #define aboutitem 1
  26.  
  27. #define filemenu 129
  28. #define quititem 1
  29.  
  30. static MenuHandle happlemenu, hfilemenu;
  31.  
  32. Boolean flexitmainloop = false;
  33.  
  34.  
  35. typedef unsigned char byte;
  36.  
  37.  
  38. static Str255 apppath; /*the full path to the droplet application*/
  39.  
  40. static Str255 appname; /*just the name of the file, no path*/
  41.  
  42. static Boolean flopenhandled = false; /*when true we fall thru the main event loop*/
  43.  
  44. static AEDesc filelist; /*holds the list of files to be processed*/
  45.  
  46. static Boolean fl2click = true; /*true if we're launched by 2clicking*/
  47.     
  48.  
  49.  
  50.  
  51. static Handle getResourceAndDetach (OSType restype, short resid) { /*new in Frontier SDK 2.1*/
  52.  
  53.     Handle h;
  54.     
  55.     h = GetResource (restype, resid);
  56.     
  57.     if (h != nil)
  58.         DetachResource (h);
  59.         
  60.     return (h);
  61.     } /*getResourceAndDetach*/
  62.     
  63.     
  64. static void copystring (void *source, void *dest) {
  65.  
  66.     /*
  67.     create a copy of source in dest.  copy the length byte and
  68.     all the characters in the source string.
  69.  
  70.     assume the strings are pascal strings, with the length byte in
  71.     the first character of the string.
  72.     */
  73.     
  74.     register short n;
  75.     register byte *s = source;
  76.     register byte *d = dest;
  77.     
  78.     n = (short) s [0];
  79.     
  80.     while (n-- >= 0)
  81.         *d++ = *s++;
  82.     } /*copystring*/
  83.  
  84.  
  85. static Boolean pushstring (Str255 bssource, Str255 bsdest) {
  86.  
  87.     register short lensource = bssource [0];
  88.     register short lendest = bsdest [0];
  89.     register byte *psource, *pdest;
  90.     
  91.     if ((lensource + lendest) > 255)
  92.         return (false);
  93.     
  94.     pdest = (byte *) bsdest + (byte) lendest + 1;
  95.     
  96.     psource = (byte *) bssource + 1;
  97.     
  98.     bsdest [0] += (byte) lensource;
  99.     
  100.     while (--lensource >= 0)
  101.         *pdest++ = *psource++;
  102.     
  103.     return (true);
  104.     } /*pushstring*/
  105.     
  106.     
  107. static Boolean pushlong (long num, Str255 bsdest) {
  108.  
  109.     Str255 bsint;
  110.     
  111.     NumToString (num, bsint);
  112.     
  113.     return (pushstring (bsint, bsdest));
  114.     } /*pushlong*/
  115.     
  116.  
  117. static void clearbytes (void *pclear, long ctclear) {
  118.     
  119.     /*
  120.     do a mass memory clear
  121.     */
  122.     
  123.     register byte *p = pclear;
  124.     register long ct = ctclear;
  125.     
  126.     while (--ct >= 0)
  127.         *p++ = (byte) 0; /*tight loop*/
  128.     } /*clearbytes*/
  129.  
  130.  
  131. static Boolean frontmostapp () {
  132.     
  133.     ProcessSerialNumber currentprocess, frontprocess;
  134.     Boolean fl;
  135.     
  136.     GetCurrentProcess (¤tprocess);
  137.     
  138.     GetFrontProcess (&frontprocess);
  139.     
  140.     SameProcess (¤tprocess, &frontprocess, &fl);
  141.     
  142.     return (fl);
  143.     } /*frontmostapp*/
  144.     
  145.     
  146. static void cometofront (void) {
  147.  
  148.     if (!frontmostapp ()) {
  149.     
  150.         register short i;
  151.         ProcessSerialNumber psn;
  152.         EventRecord ev;
  153.         
  154.         GetCurrentProcess (&psn);
  155.         
  156.         SetFrontProcess (&psn);
  157.         
  158.         for (i = 1; i <= 3; i++)
  159.             WaitNextEvent (nullEvent, &ev, 1, nil);    
  160.         }
  161.     } /*cometofront*/
  162.     
  163.     
  164. typedef struct versionRecord {
  165.  
  166.     unsigned short majorRev: 8; 
  167.     
  168.     unsigned short minorRev: 4;    
  169.     
  170.     unsigned short bugFixRev: 4; 
  171.     
  172.     unsigned short reserved: 15;
  173.     
  174.     unsigned short flFrontier: 1; /*true if it's Frontier, false if it's Runtime*/
  175.     } versionRecord;
  176.  
  177.  
  178. static Boolean getFrontierVersion (short *majorRev, short *minorRev, short *bugFixRev, Boolean *flRuntime) {
  179.     
  180.     /*
  181.     if Frontier isn't running, return false.
  182.     
  183.     if it is, return true with information about the version of Frontier that's running.
  184.     
  185.     About the Apple Event we send...
  186.     
  187.     We call a system event handler, so it's very fast. 
  188.     
  189.     It takes no parameters, and returns a long value. The high word of the long is the version 
  190.     number, packed the same way as the system version is packed into the SysEnvirons record. 
  191.     (8 bits major version, 4 bits minor version, 4 bits revision. The version 2.1.1 would 
  192.     be 0x0211.) The low word contains attributes of the server program. At this point only 
  193.     a single bit is defined: the low order bit is set if Frontier is the server; otherwise, 
  194.     Runtime is the server.
  195.     */
  196.     
  197.     AppleEvent event, reply;
  198.     Boolean flhavereply = false;
  199.     versionRecord x;
  200.     
  201.     if (!IAChandlerinstalled ('LAND', 'who?', true)) { /*it's Frontier 1.0, not Runtime*/
  202.         
  203.         *majorRev = 1;
  204.         
  205.         *minorRev = 0;
  206.         
  207.         *bugFixRev = 0;
  208.         
  209.         *flRuntime = false;
  210.         
  211.         return (true);
  212.         }
  213.  
  214.     if (!IACnewsystemverb ('LAND', 'who?', &event))
  215.         return (false);
  216.     
  217.     if (!IACsendverb (&event, &reply))
  218.         goto error;
  219.     
  220.     flhavereply = true;
  221.     
  222.     IACglobals.reply = &reply;
  223.     
  224.     IACglobals.event = &reply; /*get the string from the reply record*/
  225.         
  226.     if (!IACgetlongparam ('----', (long *) &x))
  227.         goto error;
  228.     
  229.     *majorRev = x.majorRev;
  230.     
  231.     *minorRev = x.minorRev;
  232.     
  233.     *bugFixRev = x.bugFixRev;
  234.     
  235.     *flRuntime = !x.flFrontier;
  236.     
  237.     AEDisposeDesc (&event);    
  238.     
  239.     AEDisposeDesc (&reply);
  240.     
  241.     return (true);
  242.     
  243.     error:
  244.     
  245.     AEDisposeDesc (&event);    
  246.     
  247.     if (flhavereply)
  248.         AEDisposeDesc (&reply);
  249.     
  250.     return (false);
  251.     } /*getFrontierVersion*/
  252.  
  253.  
  254. static void boldenbutton (DialogPtr pdialog, short itemnumber) {
  255.  
  256.     short itemtype;
  257.     Handle itemhandle;
  258.     Rect itemrect;
  259.     PenState savedpen;
  260.     
  261.     GetPenState (&savedpen); /*save the old pen state*/
  262.     
  263.     GetDItem (pdialog, itemnumber, &itemtype, &itemhandle, &itemrect); /*get the item’s rect*/
  264.     
  265.     InsetRect (&itemrect, -4, -4);
  266.     
  267.     PenSize (3, 3); /*make the pen fatter*/
  268.     
  269.     FrameRoundRect (&itemrect, 16, 16); /*draw the ring*/
  270.  
  271.     SetPenState (&savedpen); /*restore the pen state*/
  272.     } /*boldenbutton*/
  273.     
  274.     
  275. static void notifyuser (Str255 s) {
  276.     
  277.     DialogPtr pdialog;
  278.     short itemnumber;
  279.     
  280.     cometofront ();
  281.     
  282.     ParamText (s, "\p", "\p", "\p"); 
  283.     
  284.     pdialog = GetNewDialog (129, nil, (DialogPtr) -1L);
  285.     
  286.     ShowWindow (pdialog);    
  287.     
  288.     SetPort (pdialog);
  289.     
  290.     boldenbutton (pdialog, 1);
  291.  
  292.     SysBeep (1); /*multimedia!*/
  293.     
  294.     ModalDialog (nil, &itemnumber);
  295.  
  296.     DisposDialog (pdialog);
  297.     } /*notifyuser*/
  298.  
  299.  
  300. static Boolean IACstringtotext (s, htext) Str255 s; Handle *htext; {
  301.     
  302.     register long len;
  303.     register Handle h;
  304.     
  305.     len = s [0];
  306.     
  307.     h = NewHandle (len);
  308.     
  309.     if (h == nil)
  310.         return (false);
  311.         
  312.     BlockMove (&s [1], *h, len);
  313.     
  314.     *htext = h;
  315.     
  316.     return (true);
  317.     } /*IACstringtotext*/
  318.     
  319.     
  320. static Boolean IACcheckerror (Str255 errorstring) {
  321.     
  322.     if (IACiserrorreply (errorstring)) {
  323.         
  324.         notifyuser (errorstring);
  325.         
  326.         return (true);
  327.         }
  328.         
  329.     return (false);
  330.     } /*IACcheckerror*/
  331.     
  332.     
  333. static Boolean isfolder (Str255 fullpath) {
  334.     
  335.     CInfoPBRec pb;
  336.     OSErr ec;
  337.     
  338.     clearbytes (&pb, (long) sizeof (pb)); /*init all fields to zero*/
  339.     
  340.     pb.hFileInfo.ioNamePtr = fullpath;
  341.  
  342.     pb.hFileInfo.ioVRefNum = 0;
  343.     
  344.     ec = PBGetCatInfo (&pb, false);
  345.     
  346.     if (ec != noErr)
  347.         return (false);
  348.     
  349.     return (BitTst (&pb.dirInfo.ioFlAttrib, 3));
  350.     } /*isfolder*/
  351.  
  352.  
  353. static Boolean directorytopath (long dirid, short vnum, Str255 path) {
  354.     
  355.     CInfoPBRec block;
  356.     Str255 bsdirectory;
  357.     OSErr errcode;
  358.     
  359.     path [0] = (byte) 0; /*0-length string*/
  360.     
  361.     clearbytes (&block, (long) sizeof (block));
  362.     
  363.     block.dirInfo.ioNamePtr = bsdirectory;
  364.     
  365.     block.dirInfo.ioDrParID = dirid;
  366.     
  367.     do {
  368.         block.dirInfo.ioVRefNum = vnum;
  369.         
  370.         block.dirInfo.ioFDirIndex = -1;
  371.         
  372.         block.dirInfo.ioDrDirID = block.dirInfo.ioDrParID;
  373.         
  374.         errcode = PBGetCatInfo (&block,false);
  375.         
  376.         if (errcode != noErr)
  377.             return (false);
  378.             
  379.         if (!pushstring ("\p:", bsdirectory))
  380.             return (false);
  381.         
  382.         if (!pushstring (path, bsdirectory))
  383.             return (false);
  384.         
  385.         copystring (bsdirectory, path);
  386.         } while (block.dirInfo.ioDrDirID != fsRtDirID);
  387.     
  388.     return (true);
  389.     } /*directorytopath*/
  390.  
  391.  
  392. static Boolean getfullpath (FSSpec *fs, Str255 fullpath) {
  393.  
  394.     if ((*fs).parID == 1) { /*it's a volume*/
  395.         
  396.         copystring ((*fs).name, fullpath);
  397.         
  398.         pushstring ("\p:", fullpath);
  399.         }
  400.     else {
  401.         if (!directorytopath ((*fs).parID, (*fs).vRefNum, fullpath)) 
  402.             return (false);
  403.         
  404.         pushstring ((*fs).name, fullpath);
  405.         
  406.         if (isfolder (fullpath))
  407.             pushstring ("\p:", fullpath);        
  408.         }
  409.         
  410.     return (true);
  411.     } /*getfullpath*/
  412.     
  413.  
  414. static OSType GetProcessFullPath (void) {
  415.     
  416.     ProcessSerialNumber psn;
  417.     ProcessInfoRec info;
  418.     FSSpec fss;
  419.     
  420.     GetCurrentProcess (&psn);
  421.     
  422.     info.processInfoLength = (long) sizeof (info);
  423.     
  424.     info.processName = appname; /*place to store process name*/
  425.     
  426.     info.processAppSpec = &fss; /*place to store process filespec*/
  427.     
  428.     GetProcessInformation (&psn, &info);
  429.     
  430.     return (getfullpath (&fss, apppath));
  431.     } /*GetProcessFullPath*/
  432.     
  433.     
  434. static Boolean processfile (Str255 fullpath) {
  435.  
  436.     Boolean flhavereply = false;
  437.     AppleEvent event, reply;
  438.     Str255 bserror;
  439.     Str255 returnedstring; 
  440.     
  441.     if (!IACnewverb ('LAND', 'OHIO', 'proc', &event))
  442.         return (false);
  443.     
  444.     IACglobals.event = &event;
  445.     
  446.     if (!IACpushstringparam (fullpath, '----'))
  447.         return (false);
  448.         
  449.     if (!IACsendverb (&event, &reply))
  450.         goto error;
  451.     
  452.     flhavereply = true;
  453.     
  454.     IACglobals.reply = &reply;
  455.     
  456.     if (IACcheckerror (bserror)) 
  457.         goto error;
  458.         
  459.     IACglobals.event = &reply; /*get the string from the reply record*/
  460.     
  461.     /*
  462.     if (!IACgetstringparam ('----', returnedstring)) /%may use this for something more interesting later%/
  463.         goto error;
  464.     */
  465.     
  466.     AEDisposeDesc (&event);    
  467.     
  468.     AEDisposeDesc (&reply);
  469.     
  470.     return (true);
  471.     
  472.     error:
  473.     
  474.     AEDisposeDesc (&event);    
  475.     
  476.     if (flhavereply)
  477.         AEDisposeDesc (&reply);
  478.     
  479.     return (false);
  480.     } /*processfile*/
  481.     
  482.     
  483. static void doclosedown (void) {
  484.     
  485.     AppleEvent event, reply;
  486.     
  487.     if (IACnewverb ('LAND', 'OHIO', 'clos', &event))    
  488.         IACsendverb (&event, &reply);
  489.     } /*doclosedown*/
  490.  
  491.  
  492. static Boolean doinstall (void) {
  493.  
  494.     AEDesc desc;
  495.     OSErr ec;
  496.     Boolean flhavereply = false;
  497.     AppleEvent event, reply;
  498.     Str255 bserror;
  499.         
  500.     if (!IACnewverb ('LAND', 'OHIO', 'init', &event))
  501.         return (false);
  502.         
  503.     IACglobals.event = &event;
  504.     
  505.     desc.descriptorType = 'scpt';
  506.     
  507.     desc.dataHandle = getResourceAndDetach ('scpt', 128);
  508.     
  509.     ec = AEPutParamDesc (&event, (AEKeyword) 'prm1', &desc);
  510.     
  511.     AEDisposeDesc (&desc);
  512.     
  513.     if (ec != noErr)
  514.         return (false);
  515.     
  516.     desc.descriptorType = 'mbar';
  517.     
  518.     desc.dataHandle = getResourceAndDetach ('mbar', 128);
  519.     
  520.     ec = AEPutParamDesc (&event, (AEKeyword) 'prm2', &desc);
  521.     
  522.     AEDisposeDesc (&desc);
  523.     
  524.     if (ec != noErr)
  525.         return (false);
  526.     
  527.     if (!IACpushstringparam (apppath, 'prm3'))
  528.         return (false);
  529.         
  530.     if (!IACsendverb (&event, &reply))
  531.         goto error;
  532.     
  533.     flhavereply = true;
  534.     
  535.     IACglobals.reply = &reply;
  536.     
  537.     if (IACcheckerror (bserror)) /*syntax error or runtime error*/
  538.         goto error;
  539.         
  540.     IACglobals.event = &reply; /*get the string from the reply record*/
  541.         
  542.     AEDisposeDesc (&event);    
  543.     
  544.     AEDisposeDesc (&reply);
  545.     
  546.     return (true);
  547.     
  548.     error:
  549.     
  550.     AEDisposeDesc (&event);    
  551.     
  552.     if (flhavereply)
  553.         AEDisposeDesc (&reply);
  554.     
  555.     return (false);
  556.     } /*doinstall*/
  557.     
  558.     
  559. static Boolean dohelptext (void) {
  560.  
  561.     AEDesc desc;
  562.     OSErr ec;
  563.     Boolean flhavereply = false;
  564.     AppleEvent event, reply;
  565.     Str255 bserror;
  566.     
  567.     if (!IACnewverb ('LAND', 'OHIO', 'help', &event))
  568.         return (false);
  569.         
  570.     IACglobals.event = &event;
  571.     
  572.     desc.descriptorType = 'wptx';
  573.     
  574.     desc.dataHandle = getResourceAndDetach ('wptx', 128);
  575.     
  576.     ec = AEPutParamDesc (&event, (AEKeyword) '----', &desc);
  577.     
  578.     AEDisposeDesc (&desc);
  579.     
  580.     if (ec != noErr)
  581.         return (false);
  582.         
  583.     desc.descriptorType = 'TEXT'; /*DW 7/21/92 -- for Runtime, push plain text on the AE*/
  584.     
  585.     desc.dataHandle = getResourceAndDetach ('TEXT', 128);
  586.     
  587.     ec = AEPutParamDesc (&event, (AEKeyword) 'RUNT', &desc);
  588.     
  589.     AEDisposeDesc (&desc);
  590.     
  591.     if (ec != noErr)
  592.         return (false);
  593.         
  594.     if (!IACsendverb (&event, &reply))
  595.         goto error;
  596.     
  597.     flhavereply = true;
  598.     
  599.     IACglobals.reply = &reply;
  600.     
  601.     if (IACcheckerror (bserror)) /*syntax error or runtime error*/
  602.         goto error;
  603.         
  604.     IACglobals.event = &reply; /*get the string from the reply record*/
  605.         
  606.     AEDisposeDesc (&event);    
  607.     
  608.     AEDisposeDesc (&reply);
  609.     
  610.     return (true);
  611.     
  612.     error:
  613.     
  614.     AEDisposeDesc (&event);    
  615.     
  616.     if (flhavereply)
  617.         AEDisposeDesc (&reply);
  618.     
  619.     return (false);
  620.     } /*dohelptext*/
  621.     
  622.     
  623. static Boolean doedit (void) {
  624.  
  625.     AEDesc desc;
  626.     OSErr ec;
  627.     Boolean flhavereply = false;
  628.     AppleEvent event, reply;
  629.     Str255 bserror;
  630.     
  631.     if (!IACnewverb ('LAND', 'OHIO', 'edit', &event))
  632.         return (false);
  633.         
  634.     if (!IACsendverb (&event, &reply))
  635.         goto error;
  636.     
  637.     flhavereply = true;
  638.     
  639.     IACglobals.reply = &reply;
  640.     
  641.     if (IACcheckerror (bserror)) /*syntax error or runtime error*/
  642.         goto error;
  643.         
  644.     IACglobals.event = &reply; /*get the string from the reply record*/
  645.         
  646.     AEDisposeDesc (&event);    
  647.     
  648.     AEDisposeDesc (&reply);
  649.     
  650.     return (true);
  651.     
  652.     error:
  653.     
  654.     AEDisposeDesc (&event);    
  655.     
  656.     if (flhavereply)
  657.         AEDisposeDesc (&reply);
  658.     
  659.     return (false);
  660.     } /*doedit*/
  661.     
  662.     
  663. static Boolean dofilelist (void) {
  664.     
  665.     long ctfiles;
  666.     DescType actualtype;
  667.     long actualsize;
  668.     AEKeyword actualkeyword;
  669.     FSSpec fs;
  670.     long i;
  671.     OSErr ec;
  672.     Str255 fullpath;
  673.     
  674.     flopenhandled = true;
  675.     
  676.     fl2click = false; /*it was a drag-and-drop*/
  677.     
  678.     ec = AECountItems (&filelist, &ctfiles);
  679.     
  680.     if (ec != noErr) 
  681.         return (ec);
  682.     
  683.     if (ctfiles <= 0)
  684.         return (noErr);
  685.     
  686.     for (i = 1; i <= ctfiles; i ++) {
  687.         
  688.         ec = AEGetNthPtr (
  689.             &filelist, i, typeFSS, &actualkeyword, &actualtype, 
  690.             
  691.             (Ptr) &fs, sizeof (fs), &actualsize);
  692.         
  693.         getfullpath (&fs, fullpath);
  694.     
  695.         if (!processfile (fullpath)) {
  696.             
  697.             doclosedown ();
  698.             
  699.             return (-1);
  700.             }
  701.         } /*for*/
  702.     
  703.     doclosedown ();
  704.     
  705.     return (noErr);
  706.     } /*dofilelist*/
  707.  
  708.  
  709. static Boolean appRunning (OSType appid) {
  710.     
  711.     /*
  712.     return true if the server application is running. 
  713.     */
  714.     
  715.     ProcessInfoRec info;
  716.     ProcessSerialNumber psn;
  717.     Str255 bsname;
  718.     FSSpec fss;
  719.     
  720.     info.processInfoLength = sizeof (info);
  721.     
  722.     info.processName = bsname; /*place to store process name*/
  723.     
  724.     info.processAppSpec = &fss; /*place to store process filespec*/
  725.     
  726.     psn.highLongOfPSN = kNoProcess;
  727.     
  728.     psn.lowLongOfPSN = kNoProcess;
  729.     
  730.     while (GetNextProcess (&psn) == noErr) {
  731.         
  732.          info.processInfoLength = sizeof (ProcessInfoRec);
  733.          
  734.         if (GetProcessInformation (&psn, &info) != noErr)
  735.             continue; /*keep going -- ignore error*/
  736.         
  737.         if (info.processSignature == appid)
  738.             return (true);
  739.         } /*while*/
  740.     
  741.     return (false); /*loop completed, no server*/
  742.     } /*appRunning*/
  743.  
  744.  
  745. static Boolean hasdesktopmanager (short vnum) {
  746.     
  747.     GetVolParmsInfoBuffer volparms;
  748.     HParamBlockRec pb;
  749.     
  750.     pb.volumeParam.ioVRefNum = vnum;
  751.     
  752.     pb.volumeParam.ioNamePtr = nil;
  753.     
  754.     pb.ioParam.ioBuffer = (Ptr) &volparms;
  755.     
  756.     pb.ioParam.ioReqCount = sizeof (volparms);
  757.     
  758.     if (PBHGetVolParmsSync (&pb) != noErr)
  759.         return (false);
  760.     
  761.     return ((volparms.vMAttrib & (1 << bHasDesktopMgr)) != 0);
  762.     } /*hasdesktopmanager*/
  763.  
  764.  
  765. static Boolean findApp (OSType appid, FSSpec *fs) {
  766.     
  767.     /*
  768.     find the app whose creator id is appid. return true if we found it, 
  769.     false otherwise.
  770.     */
  771.     
  772.     DTPBRec dt;
  773.     ParamBlockRec pb;
  774.     Str255 appfname;
  775.     
  776.     clearbytes (&pb, (long) sizeof (pb));
  777.     
  778.     while (true) {
  779.         
  780.         ++pb.volumeParam.ioVolIndex;
  781.         
  782.         if (PBGetVInfoSync (&pb) != noErr)
  783.             return (false);
  784.         
  785.         if (!hasdesktopmanager (pb.volumeParam.ioVRefNum))
  786.             continue;
  787.         
  788.         dt.ioNamePtr = NULL;
  789.         
  790.         dt.ioVRefNum = pb.volumeParam.ioVRefNum;
  791.         
  792.         if (PBDTGetPath (&dt) != noErr)
  793.             return (false);
  794.         
  795.         dt.ioNamePtr = (StringPtr) &appfname;
  796.         
  797.         dt.ioIndex = 0;
  798.         
  799.         dt.ioFileCreator = appid;
  800.         
  801.         if (PBDTGetAPPLSync (&dt) == noErr) {
  802.         
  803.             if (FSMakeFSSpec (pb.volumeParam.ioVRefNum, dt.ioAPPLParID, appfname, fs) == noErr)
  804.                 return (true);
  805.             }
  806.         } /*while*/
  807.         
  808.     return (false);
  809.     } /*findApp*/
  810.  
  811.  
  812. static Boolean launchApp (FSSpec *fs) {
  813.     
  814.     LaunchParamBlockRec pb;
  815.     OSErr errcode;
  816.     
  817.     clearbytes (&pb, (long) sizeof (pb));
  818.     
  819.     pb.launchAppSpec = fs;
  820.     
  821.     pb.launchBlockID = extendedBlock;
  822.     
  823.     pb.launchEPBLength = extendedBlockLen;
  824.     
  825.     pb.launchControlFlags = launchContinue | launchNoFileFlags/* | launchDontSwitch*/;
  826.     
  827.     return (LaunchApplication (&pb) == noErr);
  828.     } /*launchApp*/
  829.  
  830.  
  831. static Boolean launchServer (OSType serverid) {
  832.     
  833.     /*
  834.     if the application whose creator id is serverid is running, return true.
  835.     
  836.     if not, we look for the application and try to launch it. we wait until it's 
  837.     actually running and ready to receive Apple Events.
  838.     */
  839.     
  840.     FSSpec fs;
  841.     
  842.     if (appRunning (serverid))
  843.         return (true);
  844.         
  845.     if (!findApp (serverid, &fs))
  846.         return (false);
  847.         
  848.     if (!launchApp (&fs))
  849.         return (false);
  850.         
  851.     while (!appRunning (serverid)) {
  852.         
  853.         EventRecord ev;
  854.         
  855.         EventAvail (everyEvent, &ev);
  856.         } /*while*/
  857.         
  858.     return (true);
  859.     } /*launchServer*/
  860.     
  861.     
  862. static pascal OSErr handleopen (AppleEvent *event, AppleEvent *reply, long refcon) {
  863.     
  864.     OSErr ec;
  865.     
  866.     flopenhandled = true;
  867.     
  868.     fl2click = false; /*it was a drag-and-drop*/
  869.     
  870.     ec = AEGetKeyDesc (event, keyDirectObject, typeAEList, &filelist);
  871.     
  872.     return (ec);
  873.     } /*handleopen*/
  874.  
  875.  
  876. static pascal OSErr handleopenapp (AppleEvent *event, AppleEvent *reply, long refcon) {
  877.     
  878.     flopenhandled = true;
  879.     
  880.     fl2click = true; /*launched by 2clicking*/
  881.     
  882.     return (noErr);
  883.     } /*handleopenapp*/
  884.     
  885.  
  886. static void drawitemtext (DialogPtr pdialog, short itemnumber, Handle htext) {
  887.  
  888.     short itemtype;
  889.     Handle itemhandle;
  890.     Rect itemrect;
  891.     short savedfont, savedsize;
  892.     Rect r;
  893.     PenState savedpen;
  894.     short fnum;
  895.     
  896.     savedfont = (*thePort).txFont;
  897.     
  898.     savedsize = (*thePort).txSize;
  899.     
  900.     GetFNum ("\pPalatino", &fnum);
  901.     
  902.     TextFont (fnum);
  903.     
  904.     TextSize (12);
  905.     
  906.     GetDItem (pdialog, itemnumber, &itemtype, &itemhandle, &itemrect); /*get the item’s rect*/
  907.     
  908.     r = itemrect;
  909.     
  910.     InsetRect (&r, 3, 3);
  911.     
  912.     TextBox (*htext, GetHandleSize (htext), &r, 0);
  913.     
  914.     TextFont (savedfont);
  915.     
  916.     TextSize (savedsize);
  917.     
  918.     GetPenState (&savedpen); /*save the old pen state*/
  919.     
  920.     PenPat (gray);
  921.     
  922.     FrameRect (&itemrect);
  923.     
  924.     SetPenState (&savedpen);
  925.     } /*drawitemtext*/
  926.     
  927.  
  928. static void drawitemstring (DialogPtr pdialog, short itemnumber, Str255 s) {
  929.  
  930.     short itemtype;
  931.     Handle itemhandle;
  932.     Rect itemrect;
  933.     short savedfont, savedsize, savedstyle;
  934.     Rect r;
  935.     PenState savedpen;
  936.     FontInfo info;
  937.     RgnHandle rgn;
  938.         
  939.     savedfont = (*thePort).txFont;
  940.     
  941.     savedsize = (*thePort).txSize;
  942.     
  943.     savedstyle = (*thePort).txFace;
  944.     
  945.     TextFont (helvetica);
  946.     
  947.     TextSize (18);
  948.     
  949.     TextFace (bold);
  950.     
  951.     GetDItem (pdialog, itemnumber, &itemtype, &itemhandle, &itemrect); /*get the item’s rect*/
  952.     
  953.     r = itemrect;
  954.     
  955.     /*InsetRect (&r, 3, 3);*/
  956.     
  957.     GetFontInfo (&info);
  958.     
  959.     MoveTo (r.left, r.bottom - info.descent);
  960.     
  961.     GetClip (rgn = NewRgn ());
  962.     
  963.     ClipRect (&r);
  964.     
  965.     DrawString (s);
  966.     
  967.     SetClip (rgn);
  968.     
  969.     DisposeRgn (rgn);
  970.     
  971.     TextFont (savedfont);
  972.     
  973.     TextSize (savedsize);
  974.     
  975.     TextFace (savedstyle);
  976.     
  977.     GetPenState (&savedpen); /*save the old pen state*/
  978.     
  979.     PenPat (gray);
  980.     
  981.     /*FrameRect (&itemrect);*/
  982.     
  983.     SetPenState (&savedpen);
  984.     } /*drawitemstring*/
  985.     
  986.  
  987. pascal OSErr PlotIconID (Rect *r, short align, short transform, short resid) = {0x303C,0x0500,0xABC9};
  988.  
  989.  
  990. static void drawitemicon (DialogPtr pdialog, short itemnumber, short resid) {
  991.  
  992.     short itemtype;
  993.     Handle itemhandle;
  994.     Rect itemrect;
  995.         
  996.     GetDItem (pdialog, itemnumber, &itemtype, &itemhandle, &itemrect); /*get the item’s rect*/
  997.     
  998.     PlotIconID (&itemrect, 0, 0, resid);
  999.     } /*drawitemicon*/
  1000.     
  1001.     
  1002. static void grayrect (Rect r) {
  1003.  
  1004.     PenState savedpen;
  1005.     
  1006.     GetPenState (&savedpen); /*save the old pen state*/
  1007.     
  1008.     PenMode (patBic);
  1009.     
  1010.     PenPat (gray);
  1011.     
  1012.     PaintRect (&r);
  1013.     
  1014.     SetPenState (&savedpen);
  1015.     } /*grayrect*/
  1016.     
  1017.  
  1018. static void disabledialogitem (DialogPtr pdialog, short itemnumber) {
  1019.     
  1020.     short itemtype;
  1021.     Handle itemhandle;
  1022.     Rect itemrect;
  1023.  
  1024.     GetDItem (pdialog, itemnumber, &itemtype, &itemhandle, &itemrect);
  1025.     
  1026.     if (itemtype < itemDisable) { /*it is enabled, disable it*/
  1027.     
  1028.         SetDItem (pdialog, itemnumber, itemtype + itemDisable, itemhandle, &itemrect);
  1029.         }
  1030.     
  1031.     grayrect (itemrect);
  1032.     } /*disabledialogitem*/
  1033.     
  1034.  
  1035. static void handledrag (EventRecord *ev, WindowPtr w) {
  1036.     
  1037.     Rect r;
  1038.  
  1039.     r = qd.screenBits.bounds; 
  1040.     
  1041.     r.top = r.top + GetMBarHeight (); 
  1042.     
  1043.     InsetRect (&r, 4, 4);
  1044.     
  1045.     DragWindow (w, (*ev).where, &r);
  1046.     } /*handledrag*/
  1047.  
  1048.  
  1049. static void handlemenu (long codeword) {
  1050.     
  1051.     register short idmenu, iditem;
  1052.     
  1053.     iditem = LoWord (codeword);
  1054.     
  1055.     idmenu = HiWord (codeword);
  1056.     
  1057.     if (SharedMenuHit (idmenu, iditem)) /*See Step #3*/    
  1058.         goto exit;
  1059.     
  1060.     switch (idmenu) {
  1061.     
  1062.         case applemenu: 
  1063.             switch (iditem) {
  1064.                 
  1065.                 case aboutitem:
  1066.                     notifyuser (*GetString (130));
  1067.                     
  1068.                     break;
  1069.             
  1070.                 default: {
  1071.                 
  1072.                     Str255 s;
  1073.                     
  1074.                     GetItem (happlemenu, iditem, s);
  1075.                     
  1076.                     OpenDeskAcc (s);
  1077.                     
  1078.                     break;
  1079.                     }
  1080.                 } /*switch*/
  1081.             
  1082.             break; /*apple menu*/
  1083.  
  1084.         case filemenu: 
  1085.             switch (iditem) {
  1086.                 
  1087.                 case quititem:
  1088.                 
  1089.                     flexitmainloop = true;
  1090.                     
  1091.                     break;
  1092.                 } /*switch*/
  1093.             
  1094.             break; /*file menu*/
  1095.             
  1096.         } /*switching on which menu was invoked*/
  1097.         
  1098.     exit:
  1099.     
  1100.     HiliteMenu (0);
  1101.     } /*handlemenu*/
  1102.  
  1103.  
  1104. static void handlemouse (EventRecord *ev) {
  1105.  
  1106.     register short part;
  1107.     WindowPtr w;
  1108.     
  1109.     part = FindWindow ((*ev).where, &w);
  1110.     
  1111.     if (w != nil) 
  1112.     
  1113.         if (w != FrontWindow ()) { /*just like all other Mac programs*/
  1114.             
  1115.             SelectWindow (w);
  1116.                             
  1117.             return; /*the mouse click is consumed by the bringtofront operation*/
  1118.             }
  1119.     
  1120.     switch (part) {
  1121.     
  1122.         case inMenuBar: 
  1123.             handlemenu (MenuSelect ((*ev).where)); 
  1124.             
  1125.             break;
  1126.         
  1127.         case inSysWindow:
  1128.             SystemClick (ev, w); 
  1129.             
  1130.             break;
  1131.         
  1132.         case inDrag:
  1133.             handledrag (ev, w);
  1134.             
  1135.             break;
  1136.             
  1137.         } /*switch*/
  1138.     } /*handlemouse*/
  1139.     
  1140.     
  1141. static void highlightbutton (short itemnumber, Boolean flon) {
  1142.     
  1143.     short x;
  1144.     short itemtype;
  1145.     Handle itemhandle;
  1146.     Rect itembox;
  1147.     
  1148.     GetDItem (w, itemnumber, &itemtype, &itemhandle, &itembox);
  1149.     
  1150.     if (flon)
  1151.         x = inButton;
  1152.     else
  1153.         x = 0;
  1154.     
  1155.     HiliteControl ((ControlHandle) itemhandle, x); 
  1156.     } /*highlightbutton*/
  1157.  
  1158.  
  1159. static void delayticks (short ct) {
  1160.     
  1161.     long tc;
  1162.     
  1163.     tc = TickCount () + ct;
  1164.     
  1165.     while (TickCount () < tc) {}
  1166.     } /*delayticks*/
  1167.     
  1168.     
  1169. static void simulatehit (short item) {
  1170.     
  1171.     highlightbutton (item, true);
  1172.     
  1173.     delayticks (8);
  1174.     
  1175.     highlightbutton (item, false);
  1176.     } /*simulatehit*/
  1177.  
  1178.  
  1179. static Boolean handlekeystroke (EventRecord *ev) { 
  1180.  
  1181.     char ch = (*ev).message & charCodeMask;
  1182.     Boolean flcmdperiod = false;
  1183.     
  1184.     if (SharedScriptRunning ()) { /*cmd-period terminates the script*/
  1185.     
  1186.         if (((*ev).modifiers & cmdKey) && (ch == '.')) { 
  1187.             
  1188.             flcmdperiod = true;
  1189.             
  1190.             CancelSharedScript (); /*cancel the shared menu script, if one is running*/
  1191.         
  1192.             return (true);
  1193.             }
  1194.         }
  1195.     
  1196.     if ((ch == (char) 13) || (ch == (char) 3) || (ch == 'r') || (ch == 'R')) { 
  1197.         
  1198.         /*user hit Return, Enter, r or R*/
  1199.         
  1200.         if (fl2click) /*Run button not enabled*/
  1201.             return (true);
  1202.         
  1203.         simulatehit (runitem);
  1204.     
  1205.         DisposDialog (w);
  1206.     
  1207.         w = nil;
  1208.     
  1209.         dofilelist ();
  1210.     
  1211.         return (false);
  1212.         }
  1213.         
  1214.     if ((flcmdperiod) || ((ch == 'q') || (ch == 'Q'))) { /*close the window and exit*/
  1215.     
  1216.         simulatehit (cancelitem);
  1217.         
  1218.         return (false);
  1219.         }
  1220.         
  1221.     if ((ch == 'e') || (ch == 'E')) {
  1222.         
  1223.         simulatehit (edititem);
  1224.         
  1225.         doedit ();
  1226.         
  1227.         return (true);
  1228.         }
  1229.         
  1230.     handlemenu (MenuKey (ch)); 
  1231.     
  1232.     return (true);
  1233.     } /*handlekeystroke*/
  1234.  
  1235.  
  1236. static void initmenus (void) {
  1237.     
  1238.     /*
  1239.     set up our apple and file menus.  nothing fancy.
  1240.     */
  1241.     
  1242.     happlemenu = GetMenu (applemenu); 
  1243.     
  1244.     AddResMenu (happlemenu, 'DRVR'); 
  1245.     
  1246.     InsertMenu (happlemenu, 0); 
  1247.     
  1248.     hfilemenu = GetMenu (filemenu); 
  1249.     
  1250.     InsertMenu (hfilemenu, 0);
  1251.     
  1252.     DrawMenuBar ();
  1253.     } /*initmenus*/
  1254.  
  1255.  
  1256. static void maineventloop (void) {
  1257.     
  1258.     Handle htext;
  1259.     EventRecord ev;
  1260.     DialogPtr pdialog;
  1261.     short itemhit;
  1262.     Boolean flinstalled = false;
  1263.     Str255 titlestring;
  1264.     
  1265.     initmenus ();
  1266.     
  1267.     htext = getResourceAndDetach ('TEXT', 128);
  1268.     
  1269.     w = GetNewDialog (modelessid, nil, (WindowPtr) -1);
  1270.     
  1271.     SetPort (w);
  1272.     
  1273.     SetWTitle (w, appname);
  1274.     
  1275.     copystring ("\pThe “", titlestring);
  1276.     
  1277.     pushstring (appname, titlestring);
  1278.     
  1279.     pushstring ("\p” Droplet", titlestring);
  1280.     
  1281.     while (!flexitmainloop) {
  1282.     
  1283.         SetCursor (&arrow);
  1284.         
  1285.         if (WaitNextEvent (everyEvent, &ev, 30, nil)) {
  1286.             
  1287.             if (IsDialogEvent (&ev)) {
  1288.                 
  1289.                 switch (ev.what) {    
  1290.                     
  1291.                     case updateEvt:
  1292.                         SetPort (w);
  1293.                         
  1294.                         BeginUpdate (w);
  1295.                         
  1296.                         DrawDialog (w);
  1297.     
  1298.                         if (fl2click)                     
  1299.                             disabledialogitem (w, runitem);
  1300.                         else
  1301.                             boldenbutton (w, runitem);
  1302.                         
  1303.                         /*enable Edit button if it's not Runtime running*/ {
  1304.                         
  1305.                             short majorRev, minorRev, bugFixRev;
  1306.                             Boolean flRuntime;
  1307.             
  1308.                             getFrontierVersion (&majorRev, &minorRev, &bugFixRev, &flRuntime);
  1309.                             
  1310.                             if (flRuntime)
  1311.                                 disabledialogitem (w, edititem);
  1312.                             }
  1313.                         
  1314.                         drawitemicon (w, iconitem, 128);
  1315.                         
  1316.                         drawitemstring (w, titleitem, titlestring);
  1317.  
  1318.                         drawitemtext (w, msgitem, htext);
  1319.                         
  1320.                         EndUpdate (w);
  1321.                         
  1322.                         break;
  1323.                     
  1324.                     case keyDown: case autoKey: {
  1325.                         if (!handlekeystroke (&ev))
  1326.                             goto endloop;
  1327.                         
  1328.                         break;
  1329.                         }
  1330.                         
  1331.                     default:
  1332.                         if (DialogSelect (&ev, &pdialog, &itemhit)) {
  1333.                             
  1334.                             switch (itemhit) {
  1335.                                 
  1336.                                 case runitem:
  1337.                                     DisposDialog (w);
  1338.                                     
  1339.                                     w = nil;
  1340.                                     
  1341.                                     dofilelist ();
  1342.                                     
  1343.                                     goto endloop;
  1344.                                 
  1345.                                 case cancelitem:
  1346.                                     goto endloop;
  1347.                                     
  1348.                                 case edititem:
  1349.                                     doedit ();
  1350.                                     
  1351.                                     break;
  1352.                                 } /*switch*/
  1353.                             }
  1354.                     } /*switch*/
  1355.                 } /*dialog event*/
  1356.             
  1357.             else { /*not a dialog event*/
  1358.                 
  1359.                 switch (ev.what) {    
  1360.  
  1361.                     case mouseDown:
  1362.                         handlemouse (&ev);
  1363.                         
  1364.                         break;
  1365.                     
  1366.                     case kHighLevelEvent:
  1367.                         AEProcessAppleEvent (&ev);
  1368.                         
  1369.                         break;
  1370.                     } /*switch*/
  1371.                 }
  1372.             } /*WNE returned true*/
  1373.         else {            
  1374.             if (!flinstalled) {
  1375.                 
  1376.                 flinstalled = true;
  1377.                 
  1378.                 doinstall ();
  1379.                 }
  1380.  
  1381.             CheckSharedMenus (140);
  1382.             }
  1383.         } /*while*/
  1384.  
  1385.     endloop:
  1386.     
  1387.     if (w != nil)
  1388.         DisposDialog (w);
  1389.     } /*maineventloop*/
  1390.     
  1391.     
  1392. void main (void) {
  1393.     
  1394.     long expiresat;
  1395.     
  1396.     InitGraf (&qd.thePort);
  1397.     
  1398.     InitFonts ();
  1399.     
  1400.     FlushEvents (everyEvent, 0);
  1401.     
  1402.     InitWindows ();
  1403.     
  1404.     InitMenus ();
  1405.     
  1406.     TEInit ();
  1407.     
  1408.     InitDialogs (nil);
  1409.     
  1410.     InitCursor ();
  1411.     
  1412.     if (!IAChaveappleevents ()) 
  1413.         return;
  1414.         
  1415.     InitSharedMenus ();
  1416.         
  1417.     if (!IACinstallhandler (kCoreEventClass, kAEOpenApplication, (ProcPtr) &handleopenapp))
  1418.         return;
  1419.         
  1420.     if (!IACinstallhandler (kCoreEventClass, kAEOpenDocuments, (ProcPtr) &handleopen))
  1421.         return;
  1422.         
  1423.     GetProcessFullPath ();
  1424.     
  1425.     if (!launchServer ('LAND')) { /*Frontier/Runtime isn't running and couldn't be launched*/
  1426.     
  1427.         Alert (128, nil);
  1428.         
  1429.         return;
  1430.         }
  1431.     
  1432.     expiresat = TickCount () + (1 * 60);
  1433.     
  1434.     while (!flopenhandled) { /*wait for the opendoc Apple Event to come in*/
  1435.         
  1436.         EventRecord ev;
  1437.  
  1438.         if (WaitNextEvent (everyEvent, &ev, 30, nil)) {
  1439.             
  1440.             if (ev.what == kHighLevelEvent) 
  1441.                 AEProcessAppleEvent (&ev);
  1442.             }
  1443.         
  1444.         if (TickCount () > expiresat)
  1445.             break;
  1446.         } /*while*/
  1447.     
  1448.     maineventloop ();
  1449.     } /*main*/
  1450.  
  1451.  
  1452.